package es.ucm.fdi.bdt;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;

import rice.environment.Environment;
import rice.pastry.NodeIdFactory;
import rice.pastry.PastryNode;
import rice.pastry.PastryNodeFactory;
import rice.pastry.socket.SocketPastryNodeFactory;
import rice.pastry.socket.internet.InternetPastryNodeFactory;
import rice.pastry.standard.RandomNodeIdFactory;

public class Main {


	public static void main(String[] args) {				
		 // Loads pastry settings
	    Environment env = new Environment();

	    // disable the UPnP setting (in case you are testing this on a NATted LAN)
	    // env.getParameters().setString("nat_search_policy","never");
	
		try {
		    int bootport = 55555;
		    int pastryport = 55555;

		    String addr = args[1];
		    
		    InetSocketAddress bootaddress = new InetSocketAddress(addr,bootport);		    

		    boolean internetOn = Boolean.valueOf(args[0]);
		    PastryNode pnode;
		    if (internetOn){
		    	pnode = createOrJoinInternet(pastryport, bootaddress, env);
		    } else {
		    	pnode = createOrJoin(pastryport, bootaddress, env);		    	
		    }
		    new App(pnode, env).run();
		    
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}

	/**
	 * LOCAL
	 * @param bindport
	 * @param bootaddress
	 * @param env
	 * @return
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static PastryNode createOrJoin(int bindport, InetSocketAddress bootaddress,
			Environment env) throws IOException, InterruptedException {
		
		// Generate the NodeIds Randomly
		NodeIdFactory nidFactory = new RandomNodeIdFactory(env);

		// construct the PastryNodeFactory, this is how we use
		// rice.pastry.socket
		PastryNodeFactory factory = new SocketPastryNodeFactory(nidFactory,
				bindport, env);

		// construct a node, but this does not cause it to boot
		PastryNode node = factory.newNode();

		// in later tutorials, we will register applications before calling boot
		node.boot(bootaddress);

		// the node may require sending several messages to fully boot into the
		// ring
		synchronized (node) {
			while (!node.isReady() && !node.joinFailed()) {
				// delay so we don't busy-wait
				node.wait(500);

				// abort if can't join
				if (node.joinFailed()) {
					throw new IOException(
							"Could not join the FreePastry ring.  Reason:"
									+ node.joinFailedReason());
				}
			}
		}

		System.out.println("Finished creating new node " + node);		
		return node;
	}
	
	/**
	 * INTERNET
	 * @param bindport
	 * @param bootaddress
	 * @param env
	 * @return
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static PastryNode createOrJoinInternet(int bindport, InetSocketAddress bootaddress,
			Environment env) throws IOException, InterruptedException {
		
		// Generate the NodeIds Randomly
		NodeIdFactory nidFactory = new RandomNodeIdFactory(env);

		// construct the PastryNodeFactory, this is how we use
		// rice.pastry.socket
		InternetPastryNodeFactory factory = new InternetPastryNodeFactory(nidFactory, bindport, env);
		
		// construct a node, but this does not cause it to boot
		PastryNode node = factory.newNode(new InetSocketAddress(ipExt(), bindport));

		// in later tutorials, we will register applications before calling boot
		node.boot(bootaddress);

		// the node may require sending several messages to fully boot into the
		// ring
		synchronized (node) {
			while (!node.isReady() && !node.joinFailed()) {
				// delay so we don't busy-wait
				node.wait(500);

				// abort if can't join
				if (node.joinFailed()) {
					throw new IOException(
							"Could not join the FreePastry ring.  Reason:"
									+ node.joinFailedReason());
				}
			}
		}

		System.out.println("Finished creating new node " + node);		
		return node;
	}

	public static String ipExt() {
		try {
			URL url = new URL("http://api.ipify.org");
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			BufferedReader rd = new BufferedReader(new InputStreamReader(
					conn.getInputStream()));
			return rd.readLine();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			return Inet4Address.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

}
